package tako.wisers.com.android.apis.parser;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import tako.wisers.com.android.apis.parser.xml.item.Column;
import tako.wisers.com.android.apis.parser.xml.item.Table;
import tako.wisers.com.android.apis.util.Global;

public class DBXMLParser extends XMLParserBase {
	// private final static String ROOT_TAG = "root";
	private final static String EXTERNAL_TAG = "external";
	private final static String TABLE_TAG = "table";
	private final static String COLUMN_TAG = "column";
	private final static String NAME_ATTR = "name";
	private final static String TYPE_ATTR = "type";
	private final static String KEY_ATTR = "key";
	private final static String MEMORY_ATTR = "inMemory";
	private final static String MAPPING_ATTR = "entity";
	private final static String SRC_ATTR = "src";
	private final static String DEFAULT_PATH = Global.CONF_PATH + "/db_mapping.xml";

	private Map<String, Table> tableMap = new Hashtable<String, Table>();

	private static DBXMLParser msxp;

	private DBXMLParser() {
		try {
			build(DEFAULT_PATH);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private DBXMLParser(String path) {
		try {
			build(path);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static DBXMLParser getInstance() {
		if (msxp == null) {
			msxp = new DBXMLParser();
		}
		return msxp;
	}


	protected void tagNameSwitch(Node node) {
		String name = node.getNodeName();
		if (TABLE_TAG.equalsIgnoreCase(name))
			tableTag(node);
		else if (COLUMN_TAG.equalsIgnoreCase(name))
			columnTag(node);
		else if (EXTERNAL_TAG.equalsIgnoreCase(name))
			extenalTag(node);

		parser(node.getChildNodes());
	}

	private void tableTag(Node node) {
		String name = getNodeAttribute(node, NAME_ATTR);
		String mappString = getNodeAttribute(node, MAPPING_ATTR);
		String inMemoryStr = getNodeAttribute(node, MEMORY_ATTR);
		Table table = new Table(name, mappString,
								new ArrayList<Column>(),
								(inMemoryStr != null && inMemoryStr.equals("true")));
		try {
			addTable(table);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void columnTag(Node node) {
		String name = getNodeAttribute(node, NAME_ATTR);
		String type = getNodeAttribute(node, TYPE_ATTR);
		String iskey = getNodeAttribute(node, KEY_ATTR);
		Column column = new Column(name, type);
		if (iskey != null && iskey.equalsIgnoreCase("true")) {
			column.setKeyword(true);
		}
		String key = getTableKey(node.getParentNode());
		Table table = getTable(key);
		table.addColumn(column);
	}

	private void extenalTag(Node node) {
		String src = getNodeAttribute(node, SRC_ATTR);
		DBXMLParser childXML = new DBXMLParser(src);
		Map<String, Table> tempTable = childXML.getTableMap();
		this.tableMap.putAll(tempTable);
	}

	private void addTable(Table table) throws IllegalAccessException {
		String key = table.getMapping();
		if (tableMap.containsKey(key)) {
			throw new IllegalAccessException(key + " already exist");
		}
		tableMap.put(key, table);
	}

	public Table getTable(String key) {
		if (tableMap.containsKey(key)) {
			return tableMap.get(key);
		}
		return null;
	}

	private String getTableKey(Node node) {
		if (node == null)
			return null;
		String nodeName = node.getNodeName();
		if (TABLE_TAG.equalsIgnoreCase(nodeName)) {
			return getNodeAttribute(node, MAPPING_ATTR);
		} else {
			return getTableKey(node.getParentNode());
		}
	}

	public Map<String, Table> getTableMap() {
		return tableMap;
	}
}
